from flask import Flask, request, jsonify
from flask_cors import CORS
from flask_limiter import Limiter
from flask_limiter.util import get_remote_address
import sqlite3
import json
import logging
from functools import wraps
import time
import os

app = Flask(__name__)
CORS(app)

# 配置速率限制
limiter = Limiter(
    app=app,
    key_func=get_remote_address,
    default_limits=["200 per day", "50 per hour"]
)

# 配置日志
logging.basicConfig(
    filename='places.log',
    level=logging.INFO,
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)

# 数据库配置
DATABASE = 'places.db'

def init_db():
    with sqlite3.connect(DATABASE) as conn:
        conn.execute('''
        CREATE TABLE IF NOT EXISTS places (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            name TEXT NOT NULL,
            category TEXT,
            longitude REAL NOT NULL,
            latitude REAL NOT NULL,
            description TEXT,
            attributes TEXT,
            created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
        )
        ''')

def get_db():
    db = sqlite3.connect(DATABASE)
    db.row_factory = sqlite3.Row
    return db

def db_transaction(f):
    @wraps(f)
    def decorated_function(*args, **kwargs):
        db = get_db()
        try:
            result = f(db, *args, **kwargs)
            db.commit()
            return result
        except Exception as e:
            db.rollback()
            logger.error(f"Database error: {str(e)}")
            raise
        finally:
            db.close()
    return decorated_function

# 缓存装饰器
def cache_with_timeout(timeout=300):
    def decorator(f):
        cache = {}
        @wraps(f)
        def decorated_function(*args, **kwargs):
            key = str(args) + str(kwargs)
            if key in cache:
                result, timestamp = cache[key]
                if time.time() - timestamp < timeout:
                    return result
            result = f(*args, **kwargs)
            cache[key] = (result, time.time())
            return result
        return decorated_function
    return decorator

@app.route('/places', methods=['GET'])
@limiter.limit("100/minute")
@cache_with_timeout(60)
def get_places():
    try:
        with get_db() as db:
            places = db.execute('SELECT * FROM places').fetchall()
            return jsonify({
                'status': 'success',
                'data': [{
                    'id': row['id'],
                    'name': row['name'],
                    'category': row['category'],
                    'longitude': row['longitude'],
                    'latitude': row['latitude'],
                    'description': row['description'],
                    'attributes': json.loads(row['attributes'] or '[]')
                } for row in places]
            })
    except Exception as e:
        logger.error(f"Error getting places: {str(e)}")
        return jsonify({'status': 'error', 'message': str(e)}), 500

@app.route('/places', methods=['POST'])
@limiter.limit("20/minute")
@db_transaction
def add_place(db):
    try:
        data = request.get_json()
        required_fields = ['name', 'longitude', 'latitude']
        if not all(field in data for field in required_fields):
            return jsonify({'status': 'error', 'message': '缺少必要字段'}), 400

        cursor = db.execute('''
            INSERT INTO places (name, category, longitude, latitude, description, attributes)
            VALUES (?, ?, ?, ?, ?, ?)
        ''', (
            data['name'],
            data.get('category'),
            data['longitude'],
            data['latitude'],
            data.get('description'),
            json.dumps(data.get('attributes', []))
        ))

        return jsonify({
            'status': 'success',
            'data': {'id': cursor.lastrowid}
        })
    except Exception as e:
        logger.error(f"Error adding place: {str(e)}")
        return jsonify({'status': 'error', 'message': str(e)}), 500

@app.route('/places/<int:place_id>', methods=['GET'])
@limiter.limit("100/minute")
@cache_with_timeout(60)
def get_place(place_id):
    try:
        with get_db() as db:
            place = db.execute('SELECT * FROM places WHERE id = ?', (place_id,)).fetchone()
            if place is None:
                return jsonify({'status': 'error', 'message': '地点不存在'}), 404

            return jsonify({
                'status': 'success',
                'data': {
                    'id': place['id'],
                    'name': place['name'],
                    'category': place['category'],
                    'longitude': place['longitude'],
                    'latitude': place['latitude'],
                    'description': place['description'],
                    'attributes': json.loads(place['attributes'] or '[]')
                }
            })
    except Exception as e:
        logger.error(f"Error getting place {place_id}: {str(e)}")
        return jsonify({'status': 'error', 'message': str(e)}), 500

@app.route('/places/<int:place_id>', methods=['PUT'])
@limiter.limit("20/minute")
@db_transaction
def update_place(db, place_id):
    try:
        data = request.get_json()
        if not data:
            return jsonify({'status': 'error', 'message': '无效的请求数据'}), 400

        current = db.execute('SELECT * FROM places WHERE id = ?', (place_id,)).fetchone()
        if current is None:
            return jsonify({'status': 'error', 'message': '地点不存在'}), 404

        db.execute('''
            UPDATE places
            SET name = ?, category = ?, longitude = ?, latitude = ?, description = ?, attributes = ?
            WHERE id = ?
        ''', (
            data.get('name', current['name']),
            data.get('category', current['category']),
            data.get('longitude', current['longitude']),
            data.get('latitude', current['latitude']),
            data.get('description', current['description']),
            json.dumps(data.get('attributes', json.loads(current['attributes'] or '[]'))),
            place_id
        ))

        return jsonify({'status': 'success'})
    except Exception as e:
        logger.error(f"Error updating place {place_id}: {str(e)}")
        return jsonify({'status': 'error', 'message': str(e)}), 500

@app.route('/places/<int:place_id>', methods=['DELETE'])
@limiter.limit("20/minute")
@db_transaction
def delete_place(db, place_id):
    try:
        result = db.execute('DELETE FROM places WHERE id = ?', (place_id,))
        if result.rowcount == 0:
            return jsonify({'status': 'error', 'message': '地点不存在'}), 404

        return jsonify({'status': 'success'})
    except Exception as e:
        logger.error(f"Error deleting place {place_id}: {str(e)}")
        return jsonify({'status': 'error', 'message': str(e)}), 500

@app.route('/places/import', methods=['POST'])
@limiter.limit("5/minute")
@db_transaction
def import_places(db):
    try:
        if 'file' not in request.files:
            return jsonify({'status': 'error', 'message': '没有上传文件'}), 400

        file = request.files['file']
        if file.filename == '':
            return jsonify({'status': 'error', 'message': '没有选择文件'}), 400

        if not file.filename.endswith('.json'):
            return jsonify({'status': 'error', 'message': '仅支持JSON文件'}), 400

        data = json.load(file)
        for place in data:
            db.execute('''
                INSERT INTO places (name, category, longitude, latitude, description, attributes)
                VALUES (?, ?, ?, ?, ?, ?)
            ''', (
                place['name'],
                place.get('category'),
                place['longitude'],
                place['latitude'],
                place.get('description'),
                json.dumps(place.get('attributes', []))
            ))

        return jsonify({'status': 'success'})
    except Exception as e:
        logger.error(f"Error importing places: {str(e)}")
        return jsonify({'status': 'error', 'message': str(e)}), 500

@app.route('/places/export', methods=['GET'])
@limiter.limit("5/minute")
def export_places():
    try:
        with get_db() as db:
            places = db.execute('SELECT * FROM places').fetchall()
            data = [{
                'id': row['id'],
                'name': row['name'],
                'category': row['category'],
                'longitude': row['longitude'],
                'latitude': row['latitude'],
                'description': row['description'],
                'attributes': json.loads(row['attributes'] or '[]')
            } for row in places]

            return jsonify(data)
    except Exception as e:
        logger.error(f"Error exporting places: {str(e)}")
        return jsonify({'status': 'error', 'message': str(e)}), 500

if __name__ == '__main__':
    init_db()
    app.run(debug=True, port=5000) 